www.gusucode.com > 24Beta 虚拟主机版 1.0.0 Beta源码程序 > 24Beta 虚拟主机版 1.0.0 Beta源码程序/24Beta-1.0.0-vhost/library/framework/base/CErrorHandler.php
<?php /** * This file contains the error handler application component. * * @author Qiang Xue <qiang.xue@gmail.com> * @link http://www.yiiframework.com/ * @copyright Copyright © 2008-2009 Yii Software LLC * @license http://www.yiiframework.com/license/ */ /** * CErrorHandler handles uncaught PHP errors and exceptions. * * It displays these errors using appropriate views based on the * nature of the error and the mode the application runs at. * It also chooses the most preferred language for displaying the error. * * CErrorHandler uses two sets of views: * <ul> * <li>development views, named as <code>exception.php</code>; * <li>production views, named as <code>error<StatusCode>.php</code>; * </ul> * where <StatusCode> stands for the HTTP error code (e.g. error500.php). * Localized views are named similarly but located under a subdirectory * whose name is the language code (e.g. zh_cn/error500.php). * * Development views are displayed when the application is in debug mode * (i.e. YII_DEBUG is defined as true). Detailed error information with source code * are displayed in these views. Production views are meant to be shown * to end-users and are used when the application is in production mode. * For security reasons, they only display the error message without any * sensitive information. * * CErrorHandler looks for the view templates from the following locations in order: * <ol> * <li><code>themes/ThemeName/views/system</code>: when a theme is active.</li> * <li><code>protected/views/system</code></li> * <li><code>framework/views</code></li> * </ol> * If the view is not found in a directory, it will be looked for in the next directory. * * The property {@link maxSourceLines} can be changed to specify the number * of source code lines to be displayed in development views. * * CErrorHandler is a core application component that can be accessed via * {@link CApplication::getErrorHandler()}. * * @author Qiang Xue <qiang.xue@gmail.com> * @version $Id: CErrorHandler.php 1053 2009-05-23 02:34:03Z qiang.xue $ * @package system.base * @since 1.0 */ class CErrorHandler extends CApplicationComponent { /** * @var integer maximum number source code lines to be displayed. Defaults to 25. */ public $maxSourceLines=25; /** * @var string the application administrator information (could be a name or email link). It is displayed in error pages to end users. Defaults to 'the webmaster'. */ public $adminInfo='the webmaster'; /** * @var boolean whether to discard any existing page output before error display. Defaults to true. */ public $discardOutput=true; /** * @var string the route (e.g. 'site/error') to the controller action that will be used to display external errors. * Inside the action, it can retrieve the error information by Yii::app()->errorHandler->error. * This property defaults to null, meaning CErrorHandler will handle the error display. * @since 1.0.6 */ public $errorAction; private $_error; /** * Handles the exception/error event. * This method is invoked by the application whenever it captures * an exception or PHP error. * @param CEvent the event containing the exception/error information */ public function handle($event) { // set event as handled to prevent it from being handled by other event handlers $event->handled=true; if($this->discardOutput) { while(@ob_end_clean()) ; } if($event instanceof CExceptionEvent) $this->handleException($event->exception); else // CErrorEvent $this->handleError($event); } /** * Returns the details about the error that is currently being handled. * The error is returned in terms of an array, with the following information: * <ul> * <li>code - the HTTP status code (e.g. 403, 500)</li> * <li>type - the error type (e.g. 'CHttpException', 'PHP Error')</li> * <li>message - the error message</li> * <li>file - the name of the PHP script file where the error occurs</li> * <li>line - the line number of the code where the error occurs</li> * <li>trace - the call stack of the error</li> * <li>source - the context source code where the error occurs</li> * </ul> * @return array the error details. Null if there is no error. * @since 1.0.6 */ public function getError() { return $this->_error; } /** * Handles the exception. * @param Exception the exception captured */ protected function handleException($exception) { $app=Yii::app(); if($app instanceof CWebApplication) { if(($trace=$this->getExactTrace($exception))===null) { $fileName=$exception->getFile(); $errorLine=$exception->getLine(); } else { $fileName=$trace['file']; $errorLine=$trace['line']; } $this->_error=$data=array( 'code'=>($exception instanceof CHttpException)?$exception->statusCode:500, 'type'=>get_class($exception), 'message'=>$exception->getMessage(), 'file'=>$fileName, 'line'=>$errorLine, 'trace'=>$exception->getTraceAsString(), 'source'=>$this->getSourceLines($fileName,$errorLine), ); if(!headers_sent()) header("HTTP/1.0 {$data['code']} ".get_class($exception)); if($exception instanceof CHttpException || !YII_DEBUG) $this->render('error',$data); else $this->render('exception',$data); } else $app->displayException($exception); } /** * Handles the PHP error. * @param CErrorEvent the PHP error event */ protected function handleError($event) { $trace=debug_backtrace(); // skip the first 3 stacks as they do not tell the error position if(count($trace)>3) $trace=array_slice($trace,3); $traceString=''; foreach($trace as $i=>$t) { if(!isset($t['file'])) $t['file']='unknown'; if(!isset($t['line'])) $t['line']=0; if(!isset($t['function'])) $t['function']='unknown'; $traceString.="#$i {$t['file']}({$t['line']}): "; if(isset($t['object']) && is_object($t['object'])) $traceString.=get_class($t['object']).'->'; $traceString.="{$t['function']}()\n"; } $app=Yii::app(); if($app instanceof CWebApplication) { $this->_error=$data=array( 'code'=>500, 'type'=>'PHP Error', 'message'=>$event->message, 'file'=>$event->file, 'line'=>$event->line, 'trace'=>$traceString, 'source'=>$this->getSourceLines($event->file,$event->line), ); if(!headers_sent()) header("HTTP/1.0 500 PHP Error"); if(YII_DEBUG) $this->render('exception',$data); else $this->render('error',$data); } else $app->displayError($event->code,$event->message,$event->file,$event->line); } /** * @param Exception the uncaught exception * @return array the exact trace where the problem occurs */ protected function getExactTrace($exception) { $traces=$exception->getTrace(); $result=null; foreach($traces as $trace) { // property access exception if(isset($trace['function']) && ($trace['function']==='__get' || $trace['function']==='__set')) return $trace; } return null; } /** * Renders the view. * @param string the view name (file name without extension). * See {@link getViewFile} for how a view file is located given its name. * @param array data to be passed to the view */ protected function render($view,$data) { if($view==='error' && $this->errorAction!==null) Yii::app()->runController($this->errorAction); else { // additional information to be passed to view $data['version']=$this->getVersionInfo(); $data['time']=time(); $data['admin']=$this->adminInfo; include($this->getViewFile($view,$data['code'])); } } /** * Determines which view file should be used. * @param string view name (either 'exception' or 'error') * @param integer HTTP status code * @return string view file path */ protected function getViewFile($view,$code) { $viewPaths=array( Yii::app()->getTheme()===null ? null : Yii::app()->getTheme()->getSystemViewPath(), Yii::app() instanceof CWebApplication ? Yii::app()->getSystemViewPath() : null, YII_PATH.DIRECTORY_SEPARATOR.'views', ); foreach($viewPaths as $i=>$viewPath) { if($viewPath!==null) { $viewFile=$this->getViewFileInternal($viewPath,$view,$code,$i===2?'en_us':null); if(is_file($viewFile)) return $viewFile; } } } /** * Looks for the view under the specified directory. * @param string the directory containing the views * @param string view name (either 'exception' or 'error') * @param integer HTTP status code * @param string the language that the view file is in * @return string view file path */ protected function getViewFileInternal($viewPath,$view,$code,$srcLanguage=null) { $app=Yii::app(); if($view==='error') { $viewFile=$app->findLocalizedFile($viewPath.DIRECTORY_SEPARATOR."error{$code}.php",$srcLanguage); if(!is_file($viewFile)) $viewFile=$app->findLocalizedFile($viewPath.DIRECTORY_SEPARATOR.'error.php',$srcLanguage); } else $viewFile=$app->findLocalizedFile($viewPath.DIRECTORY_SEPARATOR."exception.php",$srcLanguage); return $viewFile; } /** * @return string server version information. If the application is in production mode, nothing is returned. */ protected function getVersionInfo() { if(YII_DEBUG) { $version='<a href="http://www.yiiframework.com/">Yii Framework</a>/'.Yii::getVersion(); if(isset($_SERVER['SERVER_SOFTWARE'])) $version=$_SERVER['SERVER_SOFTWARE'].' '.$version; } else $version=''; return $version; } /** * Returns the source lines around the error line. * At most {@link maxSourceLines} lines will be returned. * @param string source file path * @param integer the error line number * @return array source lines around the error line, indxed by line numbers */ protected function getSourceLines($file,$line) { // determine the max number of lines to display $maxLines=$this->maxSourceLines; if($maxLines<1) $maxLines=1; else if($maxLines>100) $maxLines=100; $line--; // adjust line number to 0-based from 1-based if($line<0 || ($lines=@file($file))===false || ($lineCount=count($lines))<=$line) return array(); $halfLines=(int)($maxLines/2); $beginLine=$line-$halfLines>0?$line-$halfLines:0; $endLine=$line+$halfLines<$lineCount?$line+$halfLines:$lineCount-1; $sourceLines=array(); for($i=$beginLine;$i<=$endLine;++$i) $sourceLines[$i+1]=$lines[$i]; return $sourceLines; } }